{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# numpy基础"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Numpy简介"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> * 是Python语言的一个library [numpy](http://www.numpy.org/)\n",
    "> * 主要支持矩阵操作和运算\n",
    "> * 非常高效，core代码由C语言写成\n",
    "> * pandas也是基于Numpy构建的一个library\n",
    "> * 现在比较流行的机器学习框架（例如Tensorflow/PyTorch等等），语法都与Numpy比较接近"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 目录"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> * 数组简介和数组的构造(ndarray)\n",
    "> * 数组取值和赋值\n",
    "> * 数学运算\n",
    "> * broadcasting\n",
    "> * 逻辑运算\n",
    "> * 数组高级操作\n",
    "> * 文件输入输出\n",
    "> * 随堂小项目：用Numpy写一个Softmax"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "python里面调用一个包，用import对吧, 所以我们import numpy 包:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Arrays/数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> * 看你数组的维度啦，我自己的话比较简单粗暴，一般直接把1维数组就看做向量/vector，2维数组看做2维矩阵，3维数组看做3维矩阵...\n",
    "> * 可以调用np.array去从list初始化一个数组:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 2 3]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([1, 2, 3])\n",
    "print a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<type 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "print(type(a))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "list"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type([1, 2, 3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5 2 3]\n"
     ]
    }
   ],
   "source": [
    "a[0] = 5\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3]\n",
      " [2 3 4]]\n"
     ]
    }
   ],
   "source": [
    "b = np.array([[1, 2, 3], [2, 3, 4]])\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<type 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "print(type(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L, 3L)\n"
     ]
    }
   ],
   "source": [
    "print(b.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n"
     ]
    }
   ],
   "source": [
    "print(b[0,2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "** ndarray = n dimensional array **"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]]\n"
     ]
    }
   ],
   "source": [
    "\"\"\"\n",
    "有一些内置的创建数组的函数\n",
    "\"\"\"\n",
    "a = np.zeros((2, 3))\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 1.]]\n"
     ]
    }
   ],
   "source": [
    "b = np.ones((1, 2))\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[8 8]\n",
      " [8 8]]\n"
     ]
    }
   ],
   "source": [
    "c = np.full((2, 2), 8)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 0. 0.]\n",
      " [0. 1. 0.]\n",
      " [0. 0. 1.]]\n"
     ]
    }
   ],
   "source": [
    "d = np.eye(3)\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.36000576 0.29122015]\n",
      " [0.25116107 0.57443196]\n",
      " [0.00335893 0.93474884]]\n"
     ]
    }
   ],
   "source": [
    "e = np.random.random((3,2))\n",
    "print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[5.60573206e-317 5.68612642e-316 5.52170533e-317 5.68612879e-316]\n",
      "  [2.50935111e-316 5.68613828e-316 5.52170533e-317 5.68604105e-316]\n",
      "  [2.50935111e-316 5.68614776e-316 5.52170533e-317 5.68610033e-316]]\n",
      "\n",
      " [[2.50935111e-316 5.68682206e-316 5.52170533e-317 5.68681732e-316]\n",
      "  [2.50935111e-316 5.68615488e-316 5.52170533e-317 5.68678412e-316]\n",
      "  [2.50935111e-316 5.68615725e-316 5.52170533e-317 5.68841968e-316]]]\n"
     ]
    }
   ],
   "source": [
    "f = np.empty((2, 3, 4))\n",
    "print(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L, 3L, 4L)\n"
     ]
    }
   ],
   "source": [
    "print(f.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]\n"
     ]
    }
   ],
   "source": [
    "g = np.arange(15)\n",
    "print(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(15L,)\n"
     ]
    }
   ],
   "source": [
    "print(g.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tuple"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type((2,3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "` 数组可以有不同的数据类型 `"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "int32\n"
     ]
    }
   ],
   "source": [
    "arr = np.array([1, 2, 3])\n",
    "print(arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "float64\n"
     ]
    }
   ],
   "source": [
    "arr = np.array([1, 2, 3],dtype = np.float64)\n",
    "print(arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1., 2., 3.])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "int64\n"
     ]
    }
   ],
   "source": [
    "arr = np.array([1, 2, 3],dtype = np.int64)\n",
    "print(arr.dtype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成数组时可以指定数据类型，如果不指定numpy会自动匹配合适的类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用astype复制数组并转换数据类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([1, 2, 3, 4, 5]), dtype('int32'))\n"
     ]
    }
   ],
   "source": [
    "int_arr = np.array([1, 2, 3, 4, 5])\n",
    "print(int_arr,int_arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(dtype('float64'), array([1., 2., 3., 4., 5.]))\n"
     ]
    }
   ],
   "source": [
    "float_arr = int_arr.astype(np.float64)\n",
    "print(float_arr.dtype,float_arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用astype将float转换为int时小数部分被舍弃"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 3.5  2.3  4.8 -2.2]\n"
     ]
    }
   ],
   "source": [
    "float_arr = np.array([3.5, 2.3, 4.8, -2.2])\n",
    "print(float_arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([ 3,  2,  4, -2], dtype=int64), dtype('int64'))\n"
     ]
    }
   ],
   "source": [
    "int_arr = float_arr.astype(np.int64)\n",
    "print(int_arr,int_arr.dtype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用astype把字符串转换为数组，如果失败抛出异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['1.24', '2.2', '5.8', 'asas'], dtype='|S4')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "str_arr = np.array(['1.24', '2.2', '5.8', 'asas'],dtype=np.string_)\n",
    "str_arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "could not convert string to float: asas",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m\u001b[0m",
      "\u001b[1;31mValueError\u001b[0mTraceback (most recent call last)",
      "\u001b[1;32m<ipython-input-8-bb0697ecc6d8>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfloat_arr\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mstr_arr\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdtype\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfloat\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[1;32mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfloat_arr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: could not convert string to float: asas"
     ]
    }
   ],
   "source": [
    "float_arr = str_arr.astype(dtype=np.float)\n",
    "print(float_arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "astype使用其它数组的数据类型作为参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(dtype('float64'), dtype('int32'))\n"
     ]
    }
   ],
   "source": [
    "int_arr = np.arange(10)\n",
    "float_arr = np.array([2.3, 4.6, 9.8])\n",
    "print(float_arr.dtype,int_arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int_arr.astype(dtype=float_arr.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Array indexing/数组取值和赋值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Numpy提供了蛮多种取值的方式的."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3  4]\n",
      " [ 5  6  7  8]\n",
      " [ 9 10 11 12]]\n",
      "(3L, 4L)\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]])\n",
    "print(a)\n",
    "print(a.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以像list一样切片（多维数组可以从各个维度同时切片）:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[3 4]\n",
      " [7 8]]\n"
     ]
    }
   ],
   "source": [
    "b = a[0:2,2:4].copy()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[111111      4]\n",
      " [     7      8]]\n",
      "[[ 1  2  3  4]\n",
      " [ 5  6  7  8]\n",
      " [ 9 10 11 12]]\n"
     ]
    }
   ],
   "source": [
    "b[0,0] = 111111\n",
    "print(b)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建3x4的2维数组/矩阵"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你就放心大胆地去取你想要的数咯:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([5, 6, 7, 8]), (4L,))\n"
     ]
    }
   ],
   "source": [
    "row_r1 = a[1,:]\n",
    "print(row_r1, row_r1.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[5, 6, 7, 8]]), (1L, 4L))\n"
     ]
    }
   ],
   "source": [
    "row_r2 = a[1:2,:]\n",
    "print(row_r2,row_r2.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[5, 6, 7, 8]]), (1L, 4L))\n"
     ]
    }
   ],
   "source": [
    "row_r3 = a[[1],:]\n",
    "print(row_r3,row_r3.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "试试在第2个维度上切片也一样的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8],\n",
       "       [ 9, 10, 11, 12]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([ 2,  6, 10]), (3L,))\n"
     ]
    }
   ],
   "source": [
    "col_r1 = a[:,1]\n",
    "print(col_r1, col_r1.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[ 2],\n",
      "       [ 6],\n",
      "       [10]]), (3L, 1L))\n"
     ]
    }
   ],
   "source": [
    "col_r2 = a[:, 1:2]\n",
    "print(col_r2, col_r2.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面这个高级了，更自由地取值和组合，但是要看清楚一点:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]\n",
      " [5 6]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2], [3, 4], [5, 6]])\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 4 5]\n",
      "(3L,)\n"
     ]
    }
   ],
   "source": [
    "print(a[[0, 1, 2], [0, 1, 0]])\n",
    "print(a[[0, 1, 2], [0, 1, 0]].shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1 4 5]\n"
     ]
    }
   ],
   "source": [
    "print(np.array([a[0,0], a[1, 1], a[2, 0]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]\n",
      " [5 6]]\n",
      "[2 1]\n",
      "[1 2]\n"
     ]
    }
   ],
   "source": [
    "print(a)\n",
    "print(a[[0, 0], [1, 0]])\n",
    "print(np.array([a[0, 0], a[0, 1]]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "再来熟悉一下"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "先创建一个2维数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3]\n",
      " [ 4  5  6]\n",
      " [ 7  8  9]\n",
      " [10 11 12]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])\n",
    "print(a)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用下标生成一个向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.array([0, 2, 0, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你能看明白下面做的事情吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1,  6,  7, 11])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[np.arange(4), b]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "既然可以取出来，我们当然也可以对这些元素操作咯"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[11  2  3]\n",
      " [ 4  5 16]\n",
      " [17  8  9]\n",
      " [10 21 12]]\n"
     ]
    }
   ],
   "source": [
    "a[np.arange(4), b] += 10\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "比较fashion的取法之一，用条件判定去取（但是很好用）:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]\n",
      " [5 6]]\n"
     ]
    }
   ],
   "source": [
    "a = np.array([[1, 2], [3, 4], [5, 6]])\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[False False]\n",
      " [ True  True]\n",
      " [ True  True]]\n"
     ]
    }
   ],
   "source": [
    "bool_index = (a > 2)\n",
    "print(bool_index)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "用刚才的布尔型数组作为下标就可以去除符合条件的元素啦"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4L,)\n"
     ]
    }
   ],
   "source": [
    "print(a[bool_index].shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其实一句话也可以完成是不是？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[3 4 5 6]\n"
     ]
    }
   ],
   "source": [
    "print(a[a>2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "那个，真的，其实还有很多细节，其他的方式去取值，你可以看看官方文档。\n",
    "\n",
    "我们一起来来总结一下，看下面切片取值方式（对应颜色是取出来的结果）："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Datatypes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们可以用dtype来看numpy数组中元素的类型:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([1, 2]) # numpy 构建数组的时候自己会确定类型\n",
    "y = np.array([1.0, 2.0])\n",
    "z = np.array([1, 2], dtype = np.int64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(dtype('int32'), dtype('float64'), dtype('int64'))\n"
     ]
    }
   ],
   "source": [
    "print(x.dtype, y.dtype, z.dtype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "更多的内容可以读读[文档](https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数学运算"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面这些运算才是你在科学运算中经常经常会用到的，比如逐个元素的运算如下:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([[1, 2], [3, 4]],dtype = np.float64)\n",
    "y = np.array([[5, 6], [7, 8]],dtype = np.float64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 2.]\n",
      " [3. 4.]]\n",
      "[[5. 6.]\n",
      " [7. 8.]]\n"
     ]
    }
   ],
   "source": [
    "print(x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L, 2L)\n",
      "(2L, 2L)\n"
     ]
    }
   ],
   "source": [
    "print(x.shape)\n",
    "print(y.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逐元素求和有下面2种方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 6.,  8.],\n",
       "       [10., 12.]])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x+y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 6.,  8.],\n",
       "       [10., 12.]])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.add(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逐元素作差"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-4., -4.],\n",
       "       [-4., -4.]])"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x-y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-4., -4.],\n",
       "       [-4., -4.]])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.subtract(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逐元素相乘"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5., 12.],\n",
       "       [21., 32.]])"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x*y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5., 12.],\n",
       "       [21., 32.]])"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.multiply(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逐元素相除"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.2       , 0.33333333],\n",
       "       [0.42857143, 0.5       ]])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x/y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.2       , 0.33333333],\n",
       "       [0.42857143, 0.5       ]])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.divide(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.        , 1.41421356],\n",
       "       [1.73205081, 2.        ]])"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.sqrt(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "逐元素求平方根！！！\n",
    "\n",
    "那如果我要做矩阵的乘法运算怎么办！！！恩，别着急，照着下面写就可以了:\n",
    "\n",
    "[matrix multiplication](http://mathworld.wolfram.com/MatrixMultiplication.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L,)\n"
     ]
    }
   ],
   "source": [
    "v = np.array([9, 10])\n",
    "w = np.array([10, 11])\n",
    "print(v.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "求向量内积"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "200"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.dot(w)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "200"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(v, w)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "矩阵的乘法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n",
      "()\n",
      "[[5 6]\n",
      " [7 8]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1, 2], [3, 4]])\n",
    "y = np.array([[5, 6], [7, 8]])\n",
    "print(x)\n",
    "print()\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 9, 10])"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[29 67]\n"
     ]
    }
   ],
   "source": [
    "print(x.dot(v))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[19, 22],\n",
       "       [43, 50]])"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "转置和数学公式一样，简单粗暴"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4]])"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 3],\n",
       "       [2, 4]])"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.T"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "需要说明一下，1维的vector转置还是自己"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2L,)"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2L,)"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v.T.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2维的就不一样了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[1, 2, 3]]), (1L, 3L))\n"
     ]
    }
   ],
   "source": [
    "w = np.array([[1, 2, 3]])\n",
    "print(w, w.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1]\n",
      " [2]\n",
      " [3]]\n"
     ]
    }
   ],
   "source": [
    "print(w.T)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "利用转置矩阵做dot product"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.9569841 , -0.18769214, -0.7561045 ],\n",
       "       [-0.24322883, -1.22832174, -0.73581387],\n",
       "       [ 0.06596144,  0.40760423,  1.54622123],\n",
       "       [ 2.28388884,  0.71786205,  0.64440005],\n",
       "       [ 1.23823879, -0.04554456, -0.14456414],\n",
       "       [-1.20605784, -0.57051798, -1.65045219]])"
      ]
     },
     "execution_count": 76,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.random.randn(6, 3)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[9.1832888  2.77646757 4.28781606]\n",
      " [2.77646757 2.55303484 3.08676447]\n",
      " [4.28781606 3.08676447 6.66405883]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.T.dot(arr))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "shapes (6,3) and (6,3) not aligned: 3 (dim 1) != 6 (dim 0)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-78-c056d25d14d3>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0marr\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0marr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m: shapes (6,3) and (6,3) not aligned: 3 (dim 1) != 6 (dim 0)"
     ]
    }
   ],
   "source": [
    "print(np.dot(arr,arr))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "高维的tensor也可以做转置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[[ 0,  1,  2,  3],\n",
      "        [ 4,  5,  6,  7]],\n",
      "\n",
      "       [[ 8,  9, 10, 11],\n",
      "        [12, 13, 14, 15]]]), (2L, 2L, 4L))\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(16).reshape(2, 2, 4)\n",
    "print(arr, arr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2  3]\n",
      "  [ 8  9 10 11]]\n",
      "\n",
      " [[ 4  5  6  7]\n",
      "  [12 13 14 15]]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.transpose((1, 0, 2)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  4]\n",
      "  [ 1  5]\n",
      "  [ 2  6]\n",
      "  [ 3  7]]\n",
      "\n",
      " [[ 8 12]\n",
      "  [ 9 13]\n",
      "  [10 14]\n",
      "  [11 15]]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.transpose((0, 2, 1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  8]\n",
      "  [ 4 12]]\n",
      "\n",
      " [[ 1  9]\n",
      "  [ 5 13]]\n",
      "\n",
      " [[ 2 10]\n",
      "  [ 6 14]]\n",
      "\n",
      " [[ 3 11]\n",
      "  [ 7 15]]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.transpose((2, 1, 0)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  4]\n",
      "  [ 1  5]\n",
      "  [ 2  6]\n",
      "  [ 3  7]]\n",
      "\n",
      " [[ 8 12]\n",
      "  [ 9 13]\n",
      "  [10 14]\n",
      "  [11 15]]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.swapaxes(1, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2  3]\n",
      "  [ 4  5  6  7]\n",
      "  [ 8  9 10 11]]\n",
      "\n",
      " [[12 13 14 15]\n",
      "  [16 17 18 19]\n",
      "  [20 21 22 23]]]\n",
      "()\n",
      "[[0 1]\n",
      " [2 3]\n",
      " [4 5]\n",
      " [6 7]]\n"
     ]
    }
   ],
   "source": [
    "x = np.arange(24).reshape(2, 3, 4)\n",
    "y = np.arange(8).reshape(4, 2)\n",
    "print(x)\n",
    "print()\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L, 3L, 2L)\n"
     ]
    }
   ],
   "source": [
    "print(np.matmul(x, y).shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L, 3L, 2L)\n"
     ]
    }
   ],
   "source": [
    "print(np.dot(x, y).shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2L, 3L, 2L, 2L)\n"
     ]
    }
   ],
   "source": [
    "x = np.arange(24).reshape(2, 3, 4)\n",
    "y = np.arange(16).reshape(2, 4, 2)\n",
    "print(x.dot(y).shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2L, 3L, 2L)"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(x, y).shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你猜你做科学运算会最常用到的矩阵内元素的运算是什么？对啦，是求和，用 sum可以完成:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1, 2], [3, 4]])\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "print(np.sum(x))\n",
    "print(x.sum())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[4 6]\n"
     ]
    }
   ],
   "source": [
    "print(np.sum(x, axis = 0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[3 7]\n"
     ]
    }
   ],
   "source": [
    "print(np.sum(x, axis = 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.5\n",
      "[2. 3.]\n",
      "[1.5 3.5]\n"
     ]
    }
   ],
   "source": [
    "print(np.mean(x))\n",
    "print(np.mean(x, axis = 0))\n",
    "print(np.mean(x, axis = 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "还有一些其他我们可以想到的运算，比如求和，求平均，求cumulative sum，sumulative product用numpy都可以做到"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [4 6]]\n",
      "[[1 3]\n",
      " [3 7]]\n"
     ]
    }
   ],
   "source": [
    "print(x.cumsum(axis = 0))\n",
    "print(x.cumsum(axis = 1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 8]]\n",
      "[[ 1  2]\n",
      " [ 3 12]]\n"
     ]
    }
   ],
   "source": [
    "print(x.cumprod(axis = 0))\n",
    "print(x.cumprod(axis = 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我想说最基本的运算就是上面这个样子，更多的运算可能得查查[文档](https://docs.scipy.org/doc/numpy/reference/routines.math.html).\n",
    "\n",
    "其实除掉基本运算，我们经常还需要做一些操作，比如矩阵的变形，转置和重排等等:\n",
    "\n",
    "一维数组的排序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 12.54617753  -6.28953246  14.99363981  -4.15039126 -12.54866202\n",
      "  14.49243726  -0.52158168   4.69700869]\n"
     ]
    }
   ],
   "source": [
    "arr = np.random.randn(8) * 10\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-12.54866202  -6.28953246  -4.15039126  -0.52158168   4.69700869\n",
      "  12.54617753  14.49243726  14.99363981]\n"
     ]
    }
   ],
   "source": [
    "arr.sort()\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "二维数组也可以在某些维度上排序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ -2.07217733 -11.03661176  -0.09098783]\n",
      " [ 11.0650731   -9.8389993  -11.92678221]\n",
      " [-15.47924703 -10.72850179  -7.49005275]\n",
      " [  0.95594784 -11.11489174  12.13789387]\n",
      " [ -2.23020177  -7.05405543  -3.41170195]]\n"
     ]
    }
   ],
   "source": [
    "arr = np.random.randn(5, 3) * 10\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-11.03661176  -2.07217733  -0.09098783]\n",
      " [-11.92678221  -9.8389993   11.0650731 ]\n",
      " [-15.47924703 -10.72850179  -7.49005275]\n",
      " [-11.11489174   0.95594784  12.13789387]\n",
      " [ -7.05405543  -3.41170195  -2.23020177]]\n"
     ]
    }
   ],
   "source": [
    "arr.sort(1)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面我们做一个小案例，找出排序后位置在5%的数字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-1.6337837018984793\n"
     ]
    }
   ],
   "source": [
    "large_arr = np.random.randn(1000)\n",
    "large_arr.sort()\n",
    "print(large_arr[int(0.05 * len(large_arr))])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Broadcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个没想好哪个中文词最贴切，我们暂且叫它“传播吧”:\n",
    "作用是什么呢，我们设想一个场景，如果要用小的矩阵去和大的矩阵做一些操作，但是希望小矩阵能循环和大矩阵的那些块做一样的操作，那急需要Broadcasting啦\n",
    "\n",
    "我们要做一件事情，给x的每一行都逐元素加上一个向量，然后生成y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3]\n",
      " [ 4  5  6]\n",
      " [ 7  8  9]\n",
      " [10 11 12]]\n",
      "()\n",
      "[1 0 1]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])\n",
    "v = np.array([1, 0, 1])\n",
    "print(x)\n",
    "print()\n",
    "print(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  2  3]\n",
      " [ 4  5  6]\n",
      " [ 7  8  9]\n",
      " [10 11 12]]\n"
     ]
    }
   ],
   "source": [
    "y = np.empty_like(x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "比较粗暴的方式是，用for循环逐个相加"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 2  2  4]\n",
      " [ 5  5  7]\n",
      " [ 8  8 10]\n",
      " [11 11 13]]\n"
     ]
    }
   ],
   "source": [
    "for i in range(4):\n",
    "    y[i,:] = x[i,:] + v\n",
    "    \n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这种方法当然可以啦，问题是不高效嘛，如果你的x矩阵行数非常多，那就很慢的咯:\n",
    "\n",
    "Numpy broadcasting allows us to perform this computation without actually creating multiple copies of v. Consider this version, using broadcasting:\n",
    "\n",
    "因为broadcasting的存在，你上面的操作可以简单地汇总成一个求和操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "((4L, 3L), (3L,))\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 2,  2,  4],\n",
       "       [ 5,  5,  7],\n",
       "       [ 8,  8, 10],\n",
       "       [11, 11, 13]])"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(x.shape,v.shape)\n",
    "x + v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当操作两个array时，numpy会逐个比较它们的shape，在下述情况下，两arrays会兼容和输出broadcasting结果：\n",
    "相等\n",
    "其中一个为1，（进而可进行拷贝拓展已至，shape匹配）\n",
    "比如求和的时候有：\n",
    "\n",
    "```\n",
    "Image (3d array):  256 x 256 x 3\n",
    "Scale (1d array):              3\n",
    "Result (3d array): 256 x 256 x 3\n",
    "\n",
    "A      (4d array):  8 x 1 x 6 x 1\n",
    "B      (3d array):      7 x 1 x 5\n",
    "Result (4d array):  8 x 7 x 6 x 5\n",
    "\n",
    "A      (2d array):  5 x 4\n",
    "B      (1d array):      1\n",
    "Result (2d array):  5 x 4\n",
    "\n",
    "A      (2d array):  15 x 3 x 5\n",
    "B      (1d array):  15 x 1 x 5\n",
    "Result (2d array):  15 x 3 x 5\n",
    "```\n",
    "下面是一些 broadcasting 的例子:\n",
    "\n",
    "我们来理解一下broadcasting的这种用法\n",
    "先把v变形成3x1的数组/矩阵，然后就可以broadcasting加在w上了:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "((3L,), (2L,))\n"
     ]
    }
   ],
   "source": [
    "v = np.array([1, 2, 3])\n",
    "w = np.array([4, 5])\n",
    "print(v.shape, w.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[1],\n",
      "       [2],\n",
      "       [3]]), (3L, 1L))\n"
     ]
    }
   ],
   "source": [
    "v = v.reshape(3,1)\n",
    "print(v,v.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[5, 6],\n",
       "       [6, 7],\n",
       "       [7, 8]])"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v + w"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "那如果要把一个矩阵的每一行都加上一个向量呢"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[2 4 6]\n",
      " [5 7 9]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "v = np.array([1, 2, 3])\n",
    "print(x + v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([[1, 2, 3], [4, 5, 6]]) # 2x3的\n",
    "w = np.array([4, 5]) # 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5,  6,  7],\n",
       "       [ 9, 10, 11]])"
      ]
     },
     "execution_count": 122,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(x.T + w).T"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面那个操作太复杂了，其实我们可以直接这么做嘛"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5,  6,  7],\n",
       "       [ 9, 10, 11]])"
      ]
     },
     "execution_count": 123,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x + np.reshape(w,(2, 1))"
   ]
  },
  {
   "attachments": {
    "image.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "broadcasting当然可以逐元素运算了\n",
    "\n",
    "总结一下broadcasting，可以看看下面的图：\n",
    "\n",
    "![image.png](attachment:image.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 逻辑运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_arr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])\n",
    "y_arr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "metadata": {},
   "outputs": [],
   "source": [
    "cond = np.array([True,False,True,True,False])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.1 2.2 1.3 1.4 2.5]\n"
     ]
    }
   ],
   "source": [
    "print(np.where(cond, x_arr, y_arr)) #cond为True时取得x的值，否则取y的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.77462068  0.29892107  2.35681567 -0.67282247]\n",
      " [-0.32092708 -0.28802208 -0.01849555 -0.11728598]\n",
      " [-0.13048221  1.53781845 -1.14975711 -0.54653581]\n",
      " [ 2.01756544 -0.32218421  0.48484311 -0.35101678]]\n"
     ]
    }
   ],
   "source": [
    "arr = np.random.randn(4,4)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ True,  True,  True, False],\n",
       "       [False, False, False, False],\n",
       "       [False,  True, False, False],\n",
       "       [ True, False,  True, False]])"
      ]
     },
     "execution_count": 128,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr > 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  1  1 -1]\n",
      " [-1 -1 -1 -1]\n",
      " [-1  1 -1 -1]\n",
      " [ 1 -1  1 -1]]\n"
     ]
    }
   ],
   "source": [
    "print(np.where(arr > 0, 1, -1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.          1.          1.         -0.67282247]\n",
      " [-0.32092708 -0.28802208 -0.01849555 -0.11728598]\n",
      " [-0.13048221  1.         -1.14975711 -0.54653581]\n",
      " [ 1.         -0.32218421  1.         -0.35101678]]\n"
     ]
    }
   ],
   "source": [
    "print(np.where(arr > 0, 1, arr))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一些更高级的ndarray处理\n",
    "\n",
    "## 使用reshape来改变tensor的形状\n",
    "\n",
    "numpy可以很容易地把一维数组转成二维数组，三维数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([0, 1, 2, 3, 4, 5, 6, 7]), (8L,))\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(8)\n",
    "print(arr,arr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2, 3],\n",
       "       [4, 5, 6, 7]])"
      ]
     },
     "execution_count": 133,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.reshape(2, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[0, 1],\n",
       "        [2, 3]],\n",
       "\n",
       "       [[4, 5],\n",
       "        [6, 7]]])"
      ]
     },
     "execution_count": 134,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.reshape(2, 2, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(5L, 3L)\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(15)\n",
    "print(arr.reshape(5, 3).shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(5L, 3L)\n"
     ]
    }
   ],
   "source": [
    "print(arr.reshape(5, -1).shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们在某一个维度上写上-1，numpy会帮我们自动推导出正确的维度\n",
    "\n",
    "还可以从其他的ndarray中获取shape信息然后reshape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3L, 5L)\n"
     ]
    }
   ],
   "source": [
    "other_arr = np.ones((3, 5))\n",
    "print(other_arr.shape) #tuple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "高维数组可以用ravel来拉平"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0  1  2  3  4]\n",
      " [ 5  6  7  8  9]\n",
      " [10 11 12 13 14]]\n"
     ]
    }
   ],
   "source": [
    "arr = arr.reshape(other_arr.shape)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(15L,)"
      ]
     },
     "execution_count": 139,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.ravel().shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 连接两个二维数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[1, 2, 3],\n",
      "       [4, 5, 6]]), '\\n\\n', array([[ 7,  8,  9],\n",
      "       [10, 11, 12]]))\n"
     ]
    }
   ],
   "source": [
    "arr1 = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "arr2 = np.array([[7, 8, 9], [10, 11, 12]])\n",
    "print(arr1, \"\\n\\n\", arr2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3],\n",
       "       [ 4,  5,  6],\n",
       "       [ 7,  8,  9],\n",
       "       [10, 11, 12]])"
      ]
     },
     "execution_count": 143,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate([arr1, arr2], axis = 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3,  7,  8,  9],\n",
       "       [ 4,  5,  6, 10, 11, 12]])"
      ]
     },
     "execution_count": 144,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate([arr1,arr2],axis = 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所谓堆叠，参考叠盘子。。。连接的另一种表述 垂直stack与水平stack"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3],\n",
       "       [ 4,  5,  6],\n",
       "       [ 7,  8,  9],\n",
       "       [10, 11, 12]])"
      ]
     },
     "execution_count": 145,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vstack((arr1, arr2)) # vertical 垂直"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 146,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  3,  7,  8,  9],\n",
       "       [ 4,  5,  6, 10, 11, 12]])"
      ]
     },
     "execution_count": 146,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hstack((arr1, arr2)) # horizontal水平"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "拆分数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 147,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.44019987 0.21615341 0.82320706 0.93393395 0.26404054]\n",
      " [0.41557895 0.88896348 0.83417189 0.66031197 0.60123848]\n",
      " [0.24682344 0.8686701  0.42157043 0.11591717 0.3000165 ]\n",
      " [0.00122285 0.83607995 0.66008626 0.82806958 0.49758555]\n",
      " [0.08811401 0.43007264 0.48487779 0.23192329 0.84071637]]\n"
     ]
    }
   ],
   "source": [
    "arr = np.random.rand(5, 5)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[0.44019987, 0.21615341, 0.82320706, 0.93393395, 0.26404054]]), '\\n\\n', array([[0.41557895, 0.88896348, 0.83417189, 0.66031197, 0.60123848],\n",
      "       [0.24682344, 0.8686701 , 0.42157043, 0.11591717, 0.3000165 ]]), '\\n\\n', array([[0.00122285, 0.83607995, 0.66008626, 0.82806958, 0.49758555],\n",
      "       [0.08811401, 0.43007264, 0.48487779, 0.23192329, 0.84071637]]))\n"
     ]
    }
   ],
   "source": [
    "first, second, third = np.split(arr, [1, 3], axis = 0) #在垂直维度上第1和第3行上截断 生成新数组\n",
    "print(first, '\\n\\n', second, '\\n\\n', third)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "堆叠辅助"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0 1]\n",
      " [2 3]\n",
      " [4 5]]\n",
      "[[ 0.42396336  0.15475741]\n",
      " [ 0.06417192  0.20896689]\n",
      " [-0.97503894 -2.11582439]]\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(6)\n",
    "arr1 = arr.reshape((3, 2))\n",
    "arr2 = np.random.randn(3, 2)\n",
    "print(arr1)\n",
    "print(arr2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "r_用于按行堆叠"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 152,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.          1.        ]\n",
      " [ 2.          3.        ]\n",
      " [ 4.          5.        ]\n",
      " [ 0.42396336  0.15475741]\n",
      " [ 0.06417192  0.20896689]\n",
      " [-0.97503894 -2.11582439]]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(np.r_[arr1, arr2])\n",
    "print('')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "c_用于按列堆叠"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 153,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.          1.          0.42396336  0.15475741]\n",
      " [ 2.          3.          0.06417192  0.20896689]\n",
      " [ 4.          5.         -0.97503894 -2.11582439]]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(np.c_[arr1, arr2])\n",
    "print('')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "切片直接转为数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 154,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1, -5],\n",
       "       [ 2, -4],\n",
       "       [ 3, -3],\n",
       "       [ 4, -2],\n",
       "       [ 5, -1]])"
      ]
     },
     "execution_count": 154,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.c_[1:6, -5:0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用repeat来重复"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 155,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1 2]\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(3)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 0 0 1 1 1 2 2 2]\n"
     ]
    }
   ],
   "source": [
    "print(arr.repeat(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 0 1 1 1 2 2 2 2 2]\n"
     ]
    }
   ],
   "source": [
    "print(arr.repeat([2, 3, 5]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "按元素重复\n",
    "\n",
    "指定axis来重复"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.26957589 0.42116471]\n",
      " [0.86067227 0.54987413]]\n"
     ]
    }
   ],
   "source": [
    "arr = np.random.rand(2, 2)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.26957589 0.42116471]\n",
      " [0.26957589 0.42116471]\n",
      " [0.86067227 0.54987413]\n",
      " [0.86067227 0.54987413]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.repeat(2, axis = 0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.26957589 0.26957589 0.42116471 0.42116471]\n",
      " [0.86067227 0.86067227 0.54987413 0.54987413]]\n"
     ]
    }
   ],
   "source": [
    "print(arr.repeat(2, axis = 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tile: 参考贴瓷砖 [numpy tile](https://docs.scipy.org/doc/numpy/reference/generated/numpy.tile.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.26957589 0.42116471]\n",
      " [0.86067227 0.54987413]]\n",
      "\n",
      "[[0.26957589 0.42116471 0.26957589 0.42116471]\n",
      " [0.86067227 0.54987413 0.86067227 0.54987413]]\n"
     ]
    }
   ],
   "source": [
    "print(arr)\n",
    "print('')\n",
    "print(np.tile(arr, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.26957589 0.42116471 0.26957589 0.42116471 0.26957589 0.42116471]\n",
      " [0.86067227 0.54987413 0.86067227 0.54987413 0.86067227 0.54987413]\n",
      " [0.26957589 0.42116471 0.26957589 0.42116471 0.26957589 0.42116471]\n",
      " [0.86067227 0.54987413 0.86067227 0.54987413 0.86067227 0.54987413]]\n"
     ]
    }
   ],
   "source": [
    "print(np.tile(arr, (2, 3)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## numpy的文件输入输出\n",
    "\n",
    "读取csv文件作为数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2  3  4]\n",
      "  [ 5  6  7  8  9]\n",
      "  [10 11 12 13 14]\n",
      "  [15 16 17 18 19]\n",
      "  [20 21 22 23 24]]\n",
      "\n",
      " [[25 26 27 28 29]\n",
      "  [30 31 32 33 34]\n",
      "  [35 36 37 38 39]\n",
      "  [40 41 42 43 44]\n",
      "  [45 46 47 48 49]]]\n"
     ]
    }
   ],
   "source": [
    "arr = np.arange(50).reshape(2, 5, 5)\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.save('some_array', arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2  3  4]\n",
      "  [ 5  6  7  8  9]\n",
      "  [10 11 12 13 14]\n",
      "  [15 16 17 18 19]\n",
      "  [20 21 22 23 24]]\n",
      "\n",
      " [[25 26 27 28 29]\n",
      "  [30 31 32 33 34]\n",
      "  [35 36 37 38 39]\n",
      "  [40 41 42 43 44]\n",
      "  [45 46 47 48 49]]]\n"
     ]
    }
   ],
   "source": [
    "arr2 = np.load('some_array.npy')\n",
    "print(arr2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.580052  0.18673   1.040717  1.134411]\n",
      " [ 0.194163 -0.636917 -0.938659  0.124094]\n",
      " [-0.12641   0.268607 -0.695724  0.047428]\n",
      " [-1.484413  0.004176 -0.744203  0.005487]\n",
      " [ 2.302869  0.200131  1.670238 -1.88109 ]\n",
      " [-0.19323   1.047233  0.482803  0.960334]]\n"
     ]
    }
   ],
   "source": [
    "#arr = np.loadtxt('array_ex.txt', delimiter=',') 造数据不太好造 用不了 这个 delimiter\n",
    "arr = np.loadtxt('array_ex.txt')\n",
    "print(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "metadata": {},
   "outputs": [],
   "source": [
    "arr3 = np.arange(15).reshape(3, 5)\n",
    "np.savez(\"array_archive.npz\", arr=arr, b=arr2, c=arr3 )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[[ 0  1  2  3  4]\n",
      "  [ 5  6  7  8  9]\n",
      "  [10 11 12 13 14]\n",
      "  [15 16 17 18 19]\n",
      "  [20 21 22 23 24]]\n",
      "\n",
      " [[25 26 27 28 29]\n",
      "  [30 31 32 33 34]\n",
      "  [35 36 37 38 39]\n",
      "  [40 41 42 43 44]\n",
      "  [45 46 47 48 49]]]\n"
     ]
    }
   ],
   "source": [
    "arch = np.load('array_archive.npz')\n",
    "print(arch['arr'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 182,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[[ 0,  1,  2,  3,  4],\n",
       "        [ 5,  6,  7,  8,  9],\n",
       "        [10, 11, 12, 13, 14],\n",
       "        [15, 16, 17, 18, 19],\n",
       "        [20, 21, 22, 23, 24]],\n",
       "\n",
       "       [[25, 26, 27, 28, 29],\n",
       "        [30, 31, 32, 33, 34],\n",
       "        [35, 36, 37, 38, 39],\n",
       "        [40, 41, 42, 43, 44],\n",
       "        [45, 46, 47, 48, 49]]])"
      ]
     },
     "execution_count": 182,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arch['b']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 183,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4],\n",
       "       [ 5,  6,  7,  8,  9],\n",
       "       [10, 11, 12, 13, 14]])"
      ]
     },
     "execution_count": 183,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arch['c']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多个数组可以一起压缩存储"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 随堂小项目\n",
    "\n",
    "用numpy写一个softmax\n",
    "\n",
    "[什么是softmax?](cs231n.github.io/linear-classify/#softmax)\n",
    "\n",
    "> * 计算exponential\n",
    "> * 按行求和\n",
    "> * 每一行都要除以计算的和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 184,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 995.27356601  999.78141526  998.03779373 1009.40629564 1002.47068144\n",
      "   990.84413852  994.78219022 1011.4446295  1007.71248842 1010.88787738]\n",
      " [ 995.56194738  983.1816588   999.30639738  989.04729699  980.85924502\n",
      "   986.98475005 1008.21771884 1002.67831879  984.85415085 1010.59456166]\n",
      " [ 990.5230216  1000.23499077  993.01381223 1007.9017787   988.1165366\n",
      "   988.98481407 1003.65674487 1028.96571383  998.46254238  997.08177039]\n",
      " [ 988.39995839  995.91964326 1007.31704472 1012.87536584 1001.6571347\n",
      "   986.96923499 1002.64972442  993.23547928 1001.71001705 1000.07554632]\n",
      " [ 976.8304951  1005.31301074  991.50354387 1004.53995686 1001.31292472\n",
      "  1005.86240052  979.72988706  994.92030134 1000.89130023 1020.95428665]\n",
      " [1015.9285934   997.98903451  999.45997324  989.11566879 1018.80685166\n",
      "   982.45910849  999.20692622  976.60778614 1004.84402947 1016.63988998]\n",
      " [1010.87550147  998.1263737  1006.59154155  993.40256923  988.48546529\n",
      "  1001.37290524 1003.94074058  996.533633   1009.93712751  975.31795163]\n",
      " [ 993.78413852 1011.02933366 1003.95340673  999.35931447 1015.27386916\n",
      "  1005.04272661 1002.57128437 1001.32964062  998.58590349 1016.85799696]\n",
      " [1008.44873923 1034.87970245 1000.56318842 1009.2413216   980.30303518\n",
      "   987.15959085 1013.0212626  1005.48299358  985.1091292  1010.10159359]\n",
      " [1000.95207982  993.7062752   977.29504806 1004.4357756  1004.71022663\n",
      "  1006.23828629 1004.04399298 1003.82122312 1008.46239622 1000.69037964]]\n"
     ]
    }
   ],
   "source": [
    "m = np.random.randn(10, 10) * 10 + 1000\n",
    "print(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 185,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[1011.4446295 ],\n",
      "       [1010.59456166],\n",
      "       [1028.96571383],\n",
      "       [1012.87536584],\n",
      "       [1020.95428665],\n",
      "       [1018.80685166],\n",
      "       [1010.87550147],\n",
      "       [1016.85799696],\n",
      "       [1034.87970245],\n",
      "       [1008.46239622]]), (10L, 1L))\n"
     ]
    }
   ],
   "source": [
    "# np.exp(m)\n",
    "m_row_max = m.max(axis = 1).reshape(10, 1)\n",
    "print(m_row_max, m_row_max.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 186,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-16.17106349 -11.66321423 -13.40683577  -2.03833385  -8.97394805\n",
      "  -20.60049098 -16.66243927   0.          -3.73214108  -0.55675211]\n",
      " [-15.03261427 -27.41290285 -11.28816428 -21.54726467 -29.73531664\n",
      "  -23.6098116   -2.37684281  -7.91624287 -25.7404108    0.        ]\n",
      " [-38.44269223 -28.73072306 -35.95190159 -21.06393513 -40.84917722\n",
      "  -39.98089976 -25.30896895   0.         -30.50317145 -31.88394344]\n",
      " [-24.47540745 -16.95572258  -5.55832112   0.         -11.21823114\n",
      "  -25.90613085 -10.22564142 -19.63988656 -11.16534879 -12.79981952]\n",
      " [-44.12379154 -15.64127591 -29.45074278 -16.41432979 -19.64136193\n",
      "  -15.09188613 -41.22439959 -26.03398531 -20.06298642   0.        ]\n",
      " [ -2.87825826 -20.81781715 -19.34687842 -29.69118287   0.\n",
      "  -36.34774318 -19.59992544 -42.19906553 -13.96282219  -2.16696168]\n",
      " [  0.         -12.74912777  -4.28395991 -17.47293223 -22.39003617\n",
      "   -9.50259623  -6.93476089 -14.34186847  -0.93837396 -35.55754983]\n",
      " [-23.07385844  -5.8286633  -12.90459023 -17.49868249  -1.5841278\n",
      "  -11.81527035 -14.28671259 -15.52835634 -18.27209347   0.        ]\n",
      " [-26.43096322   0.         -34.31651403 -25.63838085 -54.57666727\n",
      "  -47.7201116  -21.85843985 -29.39670887 -49.77057325 -24.77810886]\n",
      " [ -7.51031641 -14.75612102 -31.16734816  -4.02662063  -3.75216959\n",
      "   -2.22410994  -4.41840324  -4.6411731    0.          -7.77201658]]\n"
     ]
    }
   ],
   "source": [
    "m = m - m_row_max\n",
    "print(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 187,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[9.48410516e-08, 8.60459467e-06, 1.50482226e-06, 1.30245538e-01,\n",
      "        1.26667115e-04, 1.13062984e-09, 5.80222504e-08, 1.00000000e+00,\n",
      "        2.39415203e-02, 5.73067303e-01],\n",
      "       [2.96086478e-07, 1.24373415e-12, 1.25202368e-05, 4.38673960e-10,\n",
      "        1.21931542e-13, 5.57685179e-11, 9.28432388e-02, 3.64770245e-04,\n",
      "        6.62340980e-12, 1.00000000e+00],\n",
      "       [2.01628025e-17, 3.32970313e-13, 2.43381478e-16, 7.11294101e-10,\n",
      "        1.81730466e-18, 4.33027874e-18, 1.01965779e-11, 1.00000000e+00,\n",
      "        5.65771360e-14, 1.42226101e-14],\n",
      "       [2.34674340e-11, 4.32736220e-08, 3.85524346e-03, 1.00000000e+00,\n",
      "        1.34271586e-05, 5.61190520e-12, 3.62293347e-05, 2.95464728e-09,\n",
      "        1.41563285e-05, 2.76127088e-06],\n",
      "       [6.87512837e-20, 1.61094303e-07, 1.62070855e-13, 7.43613302e-08,\n",
      "        2.95029129e-09, 2.79046856e-07, 1.24873630e-18, 4.93837240e-12,\n",
      "        1.93533303e-09, 1.00000000e+00],\n",
      "       [5.62326202e-02, 9.09781051e-10, 3.96056788e-09, 1.27433355e-13,\n",
      "        1.00000000e+00, 1.63823315e-16, 3.07510916e-09, 4.71171161e-19,\n",
      "        8.63024988e-07, 1.14525052e-01],\n",
      "       [1.00000000e+00, 2.90485301e-06, 1.37879547e-02, 2.57989451e-08,\n",
      "        1.88856023e-10, 7.46577493e-05, 9.73355779e-04, 5.90752631e-07,\n",
      "        3.91263529e-01, 3.61037503e-16],\n",
      "       [9.53126629e-11, 2.94200694e-03, 2.48660998e-06, 2.51430960e-08,\n",
      "        2.05126626e-01, 7.39083125e-06, 6.24251448e-07, 1.80351820e-07,\n",
      "        1.16019405e-08, 1.00000000e+00],\n",
      "       [3.32030915e-12, 1.00000000e+00, 1.24889900e-15, 7.33487422e-12,\n",
      "        1.98451582e-24, 1.88546665e-21, 3.21366194e-10, 1.71069093e-13,\n",
      "        2.42613339e-22, 1.73382016e-11],\n",
      "       [5.47407858e-04, 3.90389444e-07, 2.91200876e-14, 1.78344977e-02,\n",
      "        2.34667773e-02, 1.08163648e-01, 1.20534634e-02, 9.64637481e-03,\n",
      "        1.00000000e+00, 4.21362696e-04]]), (10L, 10L))\n"
     ]
    }
   ],
   "source": [
    "m_exp = np.exp(m)\n",
    "print(m_exp, m_exp.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 189,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([[1.72739129],\n",
      "       [1.09322083],\n",
      "       [1.        ],\n",
      "       [1.00392186],\n",
      "       [1.00000052],\n",
      "       [1.17075854],\n",
      "       [1.40610302],\n",
      "       [1.20807935],\n",
      "       [1.        ],\n",
      "       [1.17213392]]), (10L, 1L))\n"
     ]
    }
   ],
   "source": [
    "m_exp_row_sum = m_exp.sum(axis=1).reshape(10,1)\n",
    "print(m_exp_row_sum,m_exp_row_sum.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 190,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[5.49042084e-08 4.98126551e-06 8.71153088e-07 7.54001359e-02\n",
      "  7.33285596e-05 6.54530242e-10 3.35895235e-08 5.78907631e-01\n",
      "  1.38599288e-02 3.31753035e-01]\n",
      " [2.70838673e-07 1.13767879e-12 1.14526146e-05 4.01267475e-10\n",
      "  1.11534229e-13 5.10130402e-11 8.49263357e-02 3.33665657e-04\n",
      "  6.05862022e-12 9.14728275e-01]\n",
      " [2.01628025e-17 3.32970313e-13 2.43381478e-16 7.11294101e-10\n",
      "  1.81730466e-18 4.33027874e-18 1.01965779e-11 9.99999999e-01\n",
      "  5.65771359e-14 1.42226101e-14]\n",
      " [2.33757574e-11 4.31045717e-08 3.84018279e-03 9.96093457e-01\n",
      "  1.33747049e-05 5.58998205e-12 3.60878032e-05 2.94310482e-09\n",
      "  1.41010262e-05 2.75048386e-06]\n",
      " [6.87512480e-20 1.61094219e-07 1.62070771e-13 7.43612915e-08\n",
      "  2.95028975e-09 2.79046711e-07 1.24873566e-18 4.93836983e-12\n",
      "  1.93533202e-09 9.99999481e-01]\n",
      " [4.80309288e-02 7.77086835e-10 3.38290752e-09 1.08846829e-13\n",
      "  8.54147088e-01 1.39929207e-16 2.62659553e-09 4.02449475e-19\n",
      "  7.37150280e-07 9.78212397e-02]\n",
      " [7.11185444e-01 2.06588918e-06 9.80579272e-03 1.83478342e-08\n",
      "  1.34311655e-10 5.30955046e-05 6.92236462e-04 4.20134672e-07\n",
      "  2.78260926e-01 2.56764617e-16]\n",
      " [7.88960285e-11 2.43527624e-03 2.05831676e-06 2.08124540e-08\n",
      "  1.69795656e-01 6.11783592e-06 5.16730500e-07 1.49288058e-07\n",
      "  9.60362456e-09 8.27760195e-01]\n",
      " [3.32030915e-12 1.00000000e+00 1.24889900e-15 7.33487422e-12\n",
      "  1.98451582e-24 1.88546665e-21 3.21366194e-10 1.71069093e-13\n",
      "  2.42613339e-22 1.73382016e-11]\n",
      " [4.67018186e-04 3.33058737e-07 2.48436522e-14 1.52154095e-02\n",
      "  2.00205598e-02 9.22792577e-02 1.02833500e-02 8.22975483e-03\n",
      "  8.53144833e-01 3.59483407e-04]]\n"
     ]
    }
   ],
   "source": [
    "m_softmax = m_exp / m_exp_row_sum\n",
    "print(m_softmax)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 191,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n"
     ]
    }
   ],
   "source": [
    "print(m_softmax.sum(axis=1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "更多的numpy细节和用法可以查看一下官网[numpy指南](https://docs.scipy.org/doc/numpy/reference/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
